'''
Created on 3.11.2011

@author: halldor
'''
from datetime import date

class DayCountBasis(object):
    '''
    Enum class for daycount basis convention
    Parameters: 
        basis_30360
        basis_act360
        basis_act365
        basis_actact
    Returns:
    '''
    (basis_30360, basis_act360, basis_act365, basis_actact) = range(4)
#class DayCountBasis(object):
#    basis_30360   \
#  , basis_act_360 \
#  , basis_act_365 \
#  , basis_act_act = range(4)

#DayCountBasis_strings = (
#     "basis_30360"
#   , "basis_act_360"
#   , "basis_act_365"
#   , "basis_act_act"
#   )

def is_leap_year(year):
    '''
    Return True if the given year is a leap year, False otherwise.
    '''
    if year % 400 == 0:
        return True
    elif year % 100 == 0:
        return False
    elif year % 4 == 0:
        return True
    else:
        return False

def yearfraction(startdate, enddate, basis):
    '''
    Calculate the fraction of the year by the number of days between
    two dates (the startdate and enddate dates).
    Parameters: 
        startdate:    start date
        enddate:      end date
        basis:        DayCountBasis object with basis to use 
    Returns:
        Fraction of the year between the two dates.
    '''
    result = 0
    if basis == DayCountBasis.basis_act360:
        result = ((enddate - startdate).days)/360.0
    elif basis == DayCountBasis.basis_act365:
        result = (enddate - startdate).days/365.0
    elif basis == DayCountBasis.basis_actact:
        if startdate.year != enddate.year:
            firstday = date(enddate.year, 1, 1)
            lastday = date(startdate.year, 12, 31)
            result = (lastday - startdate).days/(365.0, 366.0)[is_leap_year(startdate.year)] + (int(enddate.year) - int(startdate.year) - 1) + (enddate - firstday).days/(365.0, 366.0)[is_leap_year(enddate.year)]
        else:
            result = (enddate - startdate).days/(365.0, 366.0)[is_leap_year(enddate.year)]
    elif basis == DayCountBasis.basis_30360:
        d1 = startdate.day
        d1 = int(d1)
        d2 = enddate.day
        d2 = int(d2)
        if d1 == 31:
            d1 -= 1
        if d2 == 31:
            d2 -= 1
        result = (int(d2) - int(d1)) + 30.0*(int(enddate.month) - int(startdate.month)) + 360.0*(int(enddate.year) - int(startdate.year))
        result = result / 360.0
    else:
        raise RuntimeError, "Unsupported basis"
    return result
